import * as cc from "cc";
import { ApiReturn, HttpClientTransportOptions } from "tsrpc-browser";
import { GlobalConfig } from "../../GlobalConfig";
import { GameUtils } from "../../game/utils/GameUtils";
import { ServiceType } from "../../shared/protocols/serviceProto";
import { GameEventDefine } from "../event/GameEventDefine";
import { Loger } from "../loger/Loger";
import HttpUtils from "../net_work/HttpUtils";
import { TsrpcUtils } from "../net_work/TsrpcUtils";
import LocalStorage from "../utils/LocalStorage";
import { SingletonFactory } from "../utils/SingletonFactory";
import StringUtils from "../utils/StringUtils";
import { ViewCtrlBase } from "./ViewCtrlBase";
import ViewMgr from "./ViewMgr";


export interface ServerResult {
    code: number,
    result: any,
}
export default class ViewModelBase {
    static modelName: string = null;
    viewMgr: ViewMgr = ViewMgr.getInstance();
    private _localData: any = null;

    constructor() {
        cc.assert(this.constructor["modelName"], "未指定modelName")
        this.loadStorage();
    }

    /**
     * 获得模型单例
     */
    static getInstance(): ViewModelBase {
        return SingletonFactory.getInstance(this)
    }

    clear() {

    }

    /**打开ui */
    public showView<T extends ViewCtrlBase>(ctrlClass: typeof ViewCtrlBase, params?: { [key: string]: any, hideOther?: boolean, unHideNames?: string[] }): Promise<T> {
        return this.viewMgr.showView<T>(ctrlClass, params);
    }

    /**尝试进入模块,子类重写 */
    tryEnter(params?: { [key: string]: any, hideOther?: boolean, unHideNames?: string[] }) {

    }

    /**模块是否开启,子类重写 */
    checkEnable() {
        return true;
    }

    /**Model名称 */
    getModelName() {
        return this.constructor["modelName"];
    }

    /**本地化保存数据key */
    protected _getSaveKey() {
        return `model_${this.getModelName()}`;
    }
    /**
     * @desc 加载本地存储的数据
     */
    protected loadStorage() {
        let data = LocalStorage.getObj(this._getSaveKey(), {});
        this._localData = data;
    }

    /**
     * @desc 保存数据到本地
     */
    protected save() {
        this._localData && LocalStorage.setObj(this._getSaveKey(), this._localData);
    }

    /**
     * protected 只让实现类操作数据  也就是model类型操作数据 对外提供别的方法
     * @param key 
     * @param defaultValue 
     */
    protected getLocalData(key: string, defaultValue: any = null, openId: string = "public") {
        if (!this._localData[openId]) {
            this._localData[openId] = {};
        }
        if (this._localData[openId][key] != undefined) {
            return this._localData[openId][key];
        }
        return defaultValue;
    }

    /**
     * 设置本地数据 设置成功返回 true，反之返回 false 用于是否保存数据
     * @param sKey 
     * @param value
     */
    protected setLocalData(key: string, value: any, openId: string = "public") {
        if (!this._localData[openId]) {
            this._localData[openId] = {};
        }
        if (this._localData[openId][key] && this._localData[openId][key] == value) {
            return false;//一样就不要改了
        }
        this._localData[openId][key] = value;
        this.save()
        return true;
    }

    /**
     * @desc 调用Tsrpc服务器框架的Api接口
     */
    protected callApi<T extends string & keyof ServiceType['api']>(apiName: T, req: ServiceType['api'][T]['req'], options?: HttpClientTransportOptions): Promise<ApiReturn<ServiceType['api'][T]['res']>> {
        return new Promise<ApiReturn<ServiceType['api'][T]['res']>>(async (resolve, reject) => {
            if (GlobalConfig.openLog || cc.sys.platform == cc.sys.Platform.DESKTOP_BROWSER) {
                const logObj = {
                    ApiName: apiName,
                    req: req,
                    options: options
                }
                Loger.logNet(`=================C2S=================\nModelCallApi:${this.getModelName()}\n${JSON.stringify(logObj, null, 4)}`);
            }
            //开启屏蔽层
            GameEventDefine.ON_SHOW_BLOCK.emit(true);
            let ret = await TsrpcUtils.getInstance().callApi(apiName, req, options)
            if (GlobalConfig.openLog || cc.sys.platform == cc.sys.Platform.DESKTOP_BROWSER) {
                Loger.logNet(`=================S2C=================\n${JSON.stringify(ret, null, 4)}`);
            }
            // 处理错误，异常分支
            if (!ret.isSucc) {
                Loger.error('Error: ' + ret.err.message);
                let msg = ret.err.message;
                if (ret.err.code) {
                    msg = `error_code_${ret.err.code}`
                }
                GameUtils.showTip(StringUtils.getStr(msg))
                reject(ret.err)
            } else {
                resolve(ret)
            }
            //关闭屏蔽层
            GameEventDefine.ON_SHOW_BLOCK.emit(false);
        })
    }

    httpGet(api: string, callback?: (data: any) => void, showErrorMsg: boolean = true, timeout: number = 10000) {
        const url = `${GlobalConfig.gameServerUrl}/${api}`
        HttpUtils.get(url, null, (responseJson: any) => {
            this._httpCallback(responseJson, callback, showErrorMsg)
        }, timeout);

    }

    httpPost(api: string, body: any, callback?: (data: any) => void, showErrorMsg: boolean = true, timeout: number = 10000) {
        const url = `${GlobalConfig.gameServerUrl}/${api}`
        HttpUtils.post(url, body, null, (responseJson: any) => {
            this._httpCallback(responseJson, callback, showErrorMsg)
        }, timeout);
    }

    private _httpCallback(responseJson: any, callback: (data: any, error?: any) => void, showErrorMsg: boolean = true) {
        if (responseJson) {
            if (responseJson == 404) {
                callback(null);
                return;
            } else if (responseJson == 401) {
                callback(null);
                return;
            } else if (responseJson["code"] == undefined) {
                GameUtils.showTip("当前网络不佳,请稍后再试");
                return;
            } else {
                if (responseJson["code"] == 0) {
                    if (responseJson["result"] && responseJson["result"].timeout) {
                        GameUtils.showTip("当前网络不佳,请稍后再试");
                        callback(null);
                    }

                    callback(responseJson["result"]);
                    return;
                } else {
                    Loger.log(`error code:${responseJson["code"]}`)
                    Loger.log(`error message:${responseJson["message"]}`)
                    if (showErrorMsg) {
                        GameUtils.showTip(`${responseJson["message"]}`)
                    }
                    callback(null, responseJson);
                }
            }
        } else {
            callback(null);
        }
    }

}